package com.nkym.wypan.aspect;/*
 * @ClassName LogAspect
 * @Desc TODO
 * @Author 19637
 * @Date 2023/6/1 11:07
 * @Version 1.0
 */


import com.fasterxml.jackson.core.JsonProcessingException;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;

@Aspect
@Component
public class LogAspect {

    @Pointcut("execution(public * com.nkym.wypan.controller.*Controller.*(..))")
    public void pointcut() {
    }

    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) throws JsonProcessingException {

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        log.info("------------- 开始 -------------");
        log.info("请求地址 {} {}", request.getRequestURL().toString(), request.getMethod());
        log.info("类名方法 {} {}()", signature.getDeclaringType(), method.getName());
        log.info("远程调用地址 {}", request.getRemoteAddr());
        //请求参数
        Object[] args = joinPoint.getArgs();
        Object[] arguments = new Object[args.length];
        int index = 0;

        for (Object arg : args) {
            //排除特殊类型，比如文件类型
            if (arg instanceof HttpServletRequest ||
                    arg instanceof HttpServletResponse ||
                    arg instanceof MultipartFile) {
                continue;
            }
            arguments[index++] = arg;
        }
        //todo  可以使用自定义注解来实现指定过滤字段
        //使用gson 去掉敏感字段信息
        String[] excludeProperties = {""};
        Gson gson = new GsonBuilder()
                .setExclusionStrategies(new SimpleExclusionStrategy(excludeProperties))
                .create();
        String jsonString = gson.toJson(arguments);
        log.info("请求参数{}", jsonString);
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint pcd) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = pcd.proceed();
        long endTime = System.currentTimeMillis();
        //todo  可以使用自定义注解来实现指定过滤字段
        //使用gson 去掉敏感字段信息
        if (result instanceof ResponseEntity) {
            log.info("耗时 {} ms", endTime - startTime);
            log.info("------------- 结束 -------------");
            return result;
        }
        String[] excludeProperties = {"password"};
        Gson gson = new GsonBuilder()
                .setExclusionStrategies(new SimpleExclusionStrategy(excludeProperties))
                .create();
        String jsonString = gson.toJson(result);
        log.info("返回参数{}", jsonString);
        log.info("耗时 {} ms", endTime - startTime);
        log.info("------------- 结束 -------------");
        return result;

    }
}

class SimpleExclusionStrategy implements ExclusionStrategy {
    private String[] excludeFields;

    public SimpleExclusionStrategy(String[] excludeFields) {
        this.excludeFields = excludeFields;
    }

    @Override
    public boolean shouldSkipField(FieldAttributes fieldAttributes) {
        return Arrays.asList(excludeFields).contains(fieldAttributes.getName());
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}